﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Shape.Mvp.Persistence.Conversations
{
	public enum ConversationEndMode
	{
		///<summary>
		/// Continue the conversation
		///</summary>
		Continue,
		///<summary>
		/// end and accept the changes
		///</summary>
		End,
		///<summary>
		/// end and abort the changes
		///</summary>
		Abort
	}

	public abstract class Conversationalist
	{
		private readonly IConversationContainerAccessor conversationContainerAccessor;
		private readonly IConversationFactory conversationFactory;
		private string conversationId;

		protected virtual string GetConversationId()
		{
			if (conversationId == null)
			{
				conversationId = Guid.NewGuid().ToString();
			}

			return conversationId;
		}

		protected Conversationalist(
			IConversationContainerAccessor conversationContainerAccessor, 
			IConversationFactory conversationFactory)
		{
			this.conversationContainerAccessor = conversationContainerAccessor;
			this.conversationFactory = conversationFactory;
		}

		protected IDisposable MyOwnConversation()
		{
			return MyOwnConversation(ConversationEndMode.Continue);
		}

		protected IDisposable MyOwnConversation(ConversationEndMode endMode)
		{
			return new ConversationWrapper(this, endMode);
		}

		protected IDisposable AnExistingConversation()
		{
			return new ConversationWrapper(this, ConversationEndMode.Continue);
		}

		private class ConversationWrapper : IDisposable
		{
			private readonly ConversationEndMode endMode;
			private readonly Conversationalist conversationalist;

			public ConversationWrapper(Conversationalist conversationalist, ConversationEndMode endMode)
			{
				this.conversationalist = conversationalist;
				this.endMode = endMode;

				string conversationId = conversationalist.GetConversationId();

				IConversation conversation =
					conversationalist.conversationContainerAccessor.Container.Get(conversationId) 
						?? 
					conversationalist.conversationFactory.CreateConversation(conversationId);

				conversationalist.conversationContainerAccessor.Container.SetAsCurrent(conversation);
				conversation.Resume();
			}

			public void Dispose()
			{
				IConversation c = conversationalist.conversationContainerAccessor.Container.Get(conversationalist.GetConversationId());
				switch (endMode)
				{
					case ConversationEndMode.End:
						c.End();
						break;
					case ConversationEndMode.Abort:
						c.Dispose();
						break;
					default:
						c.Pause();
						break;
				}
			}
		}
	}
}
